
#ifndef __NewSlaveWizard_h__
#define __NewSlaveWizard_h__

#include "usbcomm.h"
#include "resource.h"
#include <wakeup_usb_protocol.h>

class CWizardWelcomePage :
	public CWizard97ExteriorPageImpl<CWizardWelcomePage>
{
protected:
	typedef CWizardWelcomePage thisClass;
	typedef CWizard97ExteriorPageImpl<CWizardWelcomePage> baseClass;

public:
	CWizardWelcomePage(_U_STRINGorID title = (LPCTSTR)NULL) :
		baseClass(title)
	{ }

	enum { IDD = IDD_WIZ97_WELCOME };
	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()

	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	int OnSetActive();
	int OnWizardNext();
};

class CWizardCompletionPage :
	public CWizard97ExteriorPageImpl<CWizardCompletionPage>
{
protected:
	typedef CWizardCompletionPage thisClass;
	typedef CWizard97ExteriorPageImpl<CWizardCompletionPage> baseClass;

	CFont m_fontSummary;
	
public:

	CWizardCompletionPage(_U_STRINGorID title = (LPCTSTR)NULL) :
		baseClass(title)
	{ }

// Message Handlers
	enum { IDD = IDD_WIZ97_COMPLETION };
	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()

	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

// Overrides from base class
	int OnSetActive();
	int OnWizardBack();
	int OnWizardFinish();
};

/*static U8 crc_array[256] = {
0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 
0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, 
0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, 
0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, 
0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, 
0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, 
0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, 
0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, 
0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, 
0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, 
0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, 
0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, 
0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, 
0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, 
0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, 
0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, 
0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, 
0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, 
0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, 
0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, 
0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, 
0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, 
0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, 
0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, 
0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, 
0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, 
0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, 
0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, 
0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, 
0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, 
0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, 
0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35
};
*/

class CWizardFindingPage :
	public CWizard97InteriorPageImpl<CWizardFindingPage>
{
protected:
	typedef CWizardFindingPage thisClass;
	typedef CWizard97InteriorPageImpl<CWizardFindingPage> baseClass;

	CListViewCtrl m_listTagInfo;
	CStatic m_status;
	CUsbComm* m_pusb;
	Slave_Flash_Section m_flash_to_write;

/*	U8 crc;
	void update_crc(U8 data){
		crc = crc_array[(data ^ crc)&0xff];
	}
*/
public:



	CWizardFindingPage(CUsbComm* pusb, Slave_Flash_Section flash_to_write, _U_STRINGorID title = (LPCTSTR)NULL) :
		baseClass(title), m_waitCursor(false)
	{
/*		crc=0;
		for(int i=0;i<32;i++){
			U8 fb = *((U8*)(&flash_to_write)+i);
			update_crc(fb);
			MyTrace(_T("FB=0x%x, crc=0x%x\n"), fb, crc);
		}
*/
		m_wasListening=false;
		m_flash_to_write=flash_to_write;
		m_pusb = pusb;
		SetHeaderTitle(_T("Finding New Tags..."));
		SetHeaderSubTitle(_T(""));
		m_animationPhase=0;
		//baseClass::SetHeaderSubTitle(_T("Preview the information returned by detected tag"));
	}

	enum { IDD = IDD_WIZ97_FINDING };
	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
		MESSAGE_HANDLER(WM_DEVICECHANGE, OnDeviceChange)
		MESSAGE_HANDLER(WM_RECEIVE_USB_PACKET, OnReceiveUsbPacket)
		MESSAGE_HANDLER(WM_RECEIVE_USB_ERROR, OnReceiveUsbError)
		MESSAGE_HANDLER(WM_WRITE_USB_ERROR, OnWriteUsbError)
		MSG_WM_TIMER(OnTimer)
		CHAIN_MSG_MAP(baseClass)
		REFLECT_NOTIFICATIONS_ID_FILTERED(IDC_LIST_TAG_INFO)
	END_MSG_MAP()

	CImageList m_ilItemImages16;
	
	bool m_wasListening;

	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
		
		m_ilItemImages16.CreateFromImage( IDB_EXAMPLE16, 16, 0, RGB( 255, 0, 255 ), IMAGE_BITMAP, LR_CREATEDIBSECTION );
	
		if(m_pusb->IsListening()){
			m_pusb->StopListening();
			m_wasListening=true;
		}
		m_pusb->PushNotificationWnd(m_hWnd);

		m_status = GetDlgItem(IDC_LABEL_DESCRIPTION);
		m_listTagInfo = GetDlgItem(IDC_LIST_TAG_INFO); 
		m_listTagInfo.SetImageList(m_ilItemImages16, LVSIL_SMALL);
		m_listTagInfo.AddColumn(_T("Name                                                 "), 1);
		m_listTagInfo.AddColumn(_T("Signal Strength"), 2);
		m_listTagInfo.AddColumn(_T("Battery             "), 3);
		m_animationImages.CreateFromImage( IDB_WIZANIMATE48, 48, 0, RGB( 255, 0, 255 ), IMAGE_BITMAP, LR_CREATEDIBSECTION );
		return 0;	
	}
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
		bHandled=FALSE;
		m_pusb->turn_off_radio();
		m_pusb->PopNotificationWnd();
		
		if(m_wasListening)
			m_pusb->StartListening();

		return 0;
	}
	
	CImageList m_animationImages;
	int m_animationPhase;
	void OnTimer(UINT_PTR nIDEvent){
		if(m_animationPhase!=4){
			m_animationPhase++;
			if(m_animationPhase==4)
				m_animationPhase=0;
			::InvalidateRect(GetDlgItem(IDC_ANIMATE), NULL, TRUE);
			CString status;
			m_status.GetWindowText(status);
			if(status.GetLength()<130){
				status+=_T(".");
				m_status.SetWindowText(status);
			}
		}
	}
	LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LPDRAWITEMSTRUCT pdi = (LPDRAWITEMSTRUCT)lParam;
		CDCHandle dc = pdi->hDC;
		CPen penBorder;
		penBorder.CreatePen(PS_NULL, 1, RGB(0,0,0));
		dc.SelectPen(penBorder);
		dc.SelectBrush( GetSysColorBrush(COLOR_3DFACE) );
		pdi->rcItem.right=pdi->rcItem.left+48;
		pdi->rcItem.bottom=pdi->rcItem.top+48;
		dc.Rectangle(&pdi->rcItem);
		m_animationImages.DrawEx( m_animationPhase, pdi->hDC, pdi->rcItem, CLR_DEFAULT, CLR_DEFAULT, ILD_TRANSPARENT );
		return 0;
	}
	LRESULT OnDeviceChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		if(((int)wParam == DBT_DEVICEARRIVAL) || ((int)wParam == DBT_DEVICEREMOVEPENDING) ||
			((int)wParam == DBT_DEVICEREMOVECOMPLETE) || ((int)wParam == DBT_CONFIGCHANGED) )
		{
			DWORD err = m_pusb->attachDevice();
			if(m_pusb->IsAttached()){
				m_animationPhase=0;
				::InvalidateRect(GetDlgItem(IDC_ANIMATE), NULL, TRUE);
				m_status.SetWindowText(_T("Finding new tags .."));
				
				m_pusb->turn_on_radio_for_finding_new_slave();
				UsbPacket_OUT packet;	
				ZeroMemory(&packet, sizeof(packet));
				packet.slave_id = 0xff;
				//packet.cmd = CMD_READ_SLAVE_FLASH;
				packet.cmd = CMD_READ_SLAVE_TAG_INFO;
				m_pusb->SendPacketAsync(&packet);

			}else{
				m_animationPhase=4;
				::InvalidateRect(GetDlgItem(IDC_ANIMATE), NULL, TRUE);
				//MessageBox( _T("USB has been disconnected"), _T("Error"), MB_ICONWARNING);
				m_status.SetWindowText(_T("USB has been disconnected"));
			}
		}
		return 0;
	}

	CListArray<CSlaveProfile> m_detected_slaves;
	
	LRESULT OnReceiveUsbPacket(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		UsbPacket_IN* packet = (UsbPacket_IN*)(lParam+1);

		MyTrace(_T("USB Packet IN cmd = 0x%x, num_replies = %d, slave_id = %d, event_type = 0x%x, arssi = %d\n"),  
				packet->cmd, packet->num_replies, packet->data.event.slave_id, packet->data.event.event_type, packet->data.event.arssi);

		switch(packet->cmd){
			case CMD_WRITE_SLAVE_FLASH:
				m_waitCursor.Restore();
				m_pusb->turn_off_radio();
				if(packet->num_replies==0)
				{
					if(IDYES==MessageBox( _T("Could not receive response from the tag; Press 'Yes' if the tag has beeped and the light is no longer flashing, Press 'No' if light is still flashing. "),
						_T("Oops..."), MB_ICONWARNING|MB_YESNO))
					{
						PropSheet_SetCurSelByID(GetParent(), IDD_WIZ97_NAMING);
					}else
					{
						MessageBox( _T("Recommend changing to a new battery and try again. "), _T("Information"), MB_ICONINFORMATION|MB_OK);
					}
				}
				else if(packet->data.replies[0].flags != REPLY_OK)
				{
					MessageBox( _T("Tag is not programmable."), _T("Error"), MB_ICONERROR);
				}
				else{
					PropSheet_SetCurSelByID(GetParent(), IDD_WIZ97_NAMING);
				}
				break;
			case CMD_READ_SLAVE_TAG_INFO:
				if(packet->num_replies==0)
				{
					MyTrace(_T("Sending CMD_READ_SLAVE_TAG_INFO again\n"));
					UsbPacket_OUT packet_out;	
					ZeroMemory(&packet_out, sizeof(packet_out));
					packet_out.slave_id = 0xff;
					packet_out.cmd = CMD_READ_SLAVE_TAG_INFO;
					m_pusb->SendPacketAsync(&packet_out);
				}
				else if(packet->data.read_flash_reply.reply0.flags == REPLY_FLASH_READ){
					UCHAR description[29];
					memcpy(description, packet->data.read_taginfo_reply.taginfo.Code_Description, 28);
					description[28]=0;
					
					
					CAtlString desct = description;


					CSlaveProfile profile(true, desct, _T(""), packet->data.read_taginfo_reply.reply0.adcout, 
												packet->data.read_taginfo_reply.reply0.arssi, packet->data.read_taginfo_reply.reply0.slave_id, 
												(CSlaveProfile::TagType)packet->data.read_taginfo_reply.taginfo.Code_Tag_Type1);
					
					int nItem = m_listTagInfo.GetItemCount();
					m_detected_slaves.InsertAt(nItem, profile);
					m_listTagInfo.AddItem(nItem, 0, profile.m_Name);
					
					int nImage;
					if(profile.signalStrengthIndBm()<=-100) nImage=ITEM_IMAGE_NONE;
					else if(profile.signalStrengthIndBm()<-95) nImage=6;
					else if(profile.signalStrengthIndBm()<-85) nImage=7;
					else if(profile.signalStrengthIndBm()<-75) nImage=8;
					else if(profile.signalStrengthIndBm()<-65) nImage=9;
					else nImage=10;
					m_listTagInfo.AddItem(nItem, 1, profile.signalStrengthIndBmT(), nImage);
					
					CString bat;
					bat.Format(_T("%d%% remaining"), profile.percentBatteryRemaining());
					m_listTagInfo.AddItem(nItem, 2, bat);
					
					m_pusb->turn_off_radio();

					KillTimer(1);
					m_status.SetWindowText(_T("Found below new tag. Click Next to program association information onto this tag. The tag should beep upon successful programming."));

					this->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
				}
				break;
		}
		delete  (BYTE*)lParam;
		
		return 0;
	}
	LRESULT OnReceiveUsbError(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		LPVOID lpMsgBuf;

		if(lParam != 1167){

			FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER | 
				FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				lParam,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR) &lpMsgBuf,
				0, NULL );

			CString msg;
			msg.Format(_T("USB read failed with error %d: %s"), lParam, lpMsgBuf); 
			MessageBox(msg);

			LocalFree(lpMsgBuf);
		}

		m_pusb->detachDevice();
		m_animationPhase=4;
		return 0;
	}
	LRESULT OnWriteUsbError(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		LPVOID lpMsgBuf;

		if(lParam != 1167){

			FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER | 
				FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				lParam,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR) &lpMsgBuf,
				0, NULL );

			CString msg;
			msg.Format(_T("USB write failed with error %d: %s"), lParam, lpMsgBuf); 
			MessageBox(msg);

			LocalFree(lpMsgBuf);
		
		}else{

			m_pusb->detachDevice();
			m_animationPhase=4;

		}
		return 0;
	}
	
	int OnSetActive()
	{
		this->SetWizardButtons(PSWIZB_BACK );
		
		m_detected_slaves.RemoveAll();
		m_listTagInfo.DeleteAllItems();

		if(m_pusb->IsAttached())
			m_animationPhase=0;
		else
			m_animationPhase=4;

		//Animate_Play(GetDlgItem(IDC_ANIMATE1), 0, -1, -1);
		//Invalidate();
		SetTimer(1, 300, NULL);

		m_pusb->set_cmd_timeout_ms(4500);
		m_pusb->turn_on_radio_for_finding_new_slave();
		UsbPacket_OUT packet;	
		ZeroMemory(&packet, sizeof(packet));
		packet.slave_id = 0xff;
		packet.cmd = CMD_READ_SLAVE_TAG_INFO;
		m_pusb->SendPacketAsync(&packet);
		
		m_status.SetWindowText(_T("Finding new tags .."));
				
		// 0 = allow activate
		// -1 = go back to page that was active
		// page ID = jump to page
		return 0;
	}
	BOOL OnKillActive()
	{
		if(m_detected_slaves.GetSize()==0){
			m_pusb->turn_off_radio();
			KillTimer(1);
		}
		return FALSE;
	}

	CWaitCursor m_waitCursor;
		
	int OnWizardNext()
	{
		m_waitCursor.Set();
		m_pusb->set_cmd_timeout_ms(5000);
		m_pusb->turn_on_radio_for_finding_new_slave();
		UsbPacket_OUT packet;	
		ZeroMemory(&packet, sizeof(packet));
		packet.slave_id = 0xff;
		packet.cmd = CMD_WRITE_SLAVE_FLASH;
		packet.extra.flash_to_write = this->m_flash_to_write; 
		m_pusb->SendPacketAsync(&packet);
		
		this->SetWizardButtons(PSWIZB_BACK );
		return -1;
	}

	int OnWizardBack();
};

class CWizardNamingPage :
	public CWizard97InteriorPageImpl<CWizardNamingPage>
{
protected:
	typedef CWizardNamingPage thisClass;
	typedef CWizard97InteriorPageImpl<CWizardNamingPage> baseClass;

	U8 m_slave_id;

public:

	CString m_name;
	CString m_comment;

	CWizardNamingPage(U8 slave_id, _U_STRINGorID title = (LPCTSTR)NULL) :
		baseClass(title), m_slave_id(slave_id)
	{
		SetHeaderTitle(_T("Please name this tag"));
		SetHeaderSubTitle(_T(""));
	}
	

	enum { IDD = IDD_WIZ97_NAMING };
	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()

	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		CString tagname;
		tagname.Format(_T("Tag%d"), m_slave_id);
		::SetWindowText(GetDlgItem(IDC_EDIT_TAGNAME), tagname);
		return 0;
	}
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		CEdit tn = GetDlgItem(IDC_EDIT_TAGNAME);
		CEdit tc = GetDlgItem(IDC_EDIT_TAGCOMMENT);
		
		tn.GetWindowText(m_name);
		tc.GetWindowText(m_comment);
		return 0;
	}
	
	BOOL OnQueryCancel()
	{
		MessageBox( _T("Tag has already been associated with your Wireless Tag Manager. If you want to undo the association, please finish this wizard, then right click on the new tag, and choose \"Unassociate\""), _T("Warning"), MB_ICONWARNING);
		return TRUE;
	}

	int OnSetActive()
	{
		this->SetWizardButtons(PSWIZB_NEXT);

		return 0;
	}
	BOOL OnKillActive()
	{
		return FALSE;
	}

	int OnWizardNext()
	{
		return 0;
	}

	int OnWizardBack()
	{
		return -1;
	}

};


class CNewWizardSheet :
	public CWizard97SheetImpl<CNewWizardSheet>
{
protected:
// Typedefs
	typedef CNewWizardSheet thisClass;
	typedef CWizard97SheetImpl<CNewWizardSheet> baseClass;

public:
	CNewWizardSheet(CUsbComm* pusb, Slave_Flash_Section flash_to_write, UINT uStartPage = 0, HWND hWndParent = NULL);
	CWizardWelcomePage m_pageWelcome;
	CWizardFindingPage m_pageFinding;
	CWizardNamingPage m_pageNaming;
	CWizardCompletionPage m_pageCompletion;

};


#endif
